<!-- 
  vue2.x中实现响应式：
    Object.defineProerty 

  Object.defineProerty的缺点：
    1）一次性深度递归遍历
    2）无法监听新增属性，删除属性   Vue.set   Vue.delete
    3）无法原生原生监听数组，需要特殊处理。

  Vue3的响应式：
    1）学习Proxy语法
    2）Reflect语法
    3）Vue3如何使用proxy+relfect实现响应式

  语法：
    1）Reflect语法
      A）和Proxy能力是一一对应的。
      B）替代了Object上的工具函数
      C）规范化，标准化

    2）proxy


  proxy实现响应式：
    1）只有用于这个数据时，才会处理成响应式
    2）可监听新增和删除属性，还有其它操作
    3）可监听数组变化
    4）proxy能规避Object.defineProperty的问题
    5）Proxy无当兼容所有的浏览器，兼容性没有Object.defineProperty好。无法polyfill
 -->

<!-- <script>
  let obj = { a: 100, b: 200 }
  // Object是构造器，类。
  // getOwnPropertyNames 是一个工具方法
  // JS刚发明，把很多的工具函数放到的Object身上了
  // 其实是不合理的。
  console.log(Object.getOwnPropertyNames(obj));

  console.log("-------------");
  console.log(Reflect.ownKeys(obj));
</script> -->

<!-- <script>
  const data = {
    name: "wc",
    age: 18
  }

  // Proxy 是代理
  let proxyData = new Proxy(data, {
    get(target, key, receiver) {
      const ownKeys = Reflect.ownKeys(target); // [name,age]
      if (ownKeys.includes(key)) {
        console.log("get", key); // 只有走到这里，才去更新视图
      }

      const result = Reflect.get(target, key, receiver)
      return result;
    },
    set(target, key, val, receiver) {
      // 如果新数据和老数据是一样的，不需要处理
      if (val === target[key]) {
        return true;
      }
      console.log("set", key, val);
      const result = Reflect.set(target, key, val, receiver)
      // console.log("result",result); // result表示是否设置成功
      return result
    },
    deleteProperty(target, key) {
      console.log("delete", key);
      const result = Reflect.deleteProperty(target, key)
      return result
    },
  })

  // console.log(proxyData.name);
  console.log(proxyData.valueOf);
  // console.log(proxyData.age);
  // proxyData.name = "xq";
  // proxyData.name = "wc";

  // delete proxyData.name;
</script> -->


<script>

  // 实现响应式 vue3
  function reactive(target = {}) {
    if (typeof target !== "object" || target == null) {
      // 不是对象或数组，不需要处理，直接返回
      return target;
    }
    // 说明target是一个对象或数组
    let proxyConf = {
      get(target, key, receiver) {
        const ownKeys = Reflect.ownKeys(target); // [name,age]
        if (ownKeys.includes(key)) {
          console.log("get", key); // 只有走到这里，才去更新视图
        }

        const result = Reflect.get(target, key, receiver)
        // console.log("result:", result);
        // 在vue2中，一次性全部深度递归处理成响应式
        // 在vue3中，什么时候用什么时候递归，处理成响应式
        return reactive(result);
      },
      set(target, key, val, receiver) {
        // 如果新数据和老数据是一样的，不需要处理
        if (val === target[key]) {
          return true;
        }

        const ownKeys = Reflect.ownKeys(target); // [name,age]
        if (ownKeys.includes(key)) {
          console.log("有key 修改", key); // 只有走到这里，才去更新视图
        } else {
          console.log("无key 新增", key);
        }


        console.log("set", key, val);
        const result = Reflect.set(target, key, val, receiver)
        // console.log("result",result); // result表示是否设置成功
        return result
      },
      deleteProperty(target, key) {
        console.log("delete", key);
        const result = Reflect.deleteProperty(target, key)
        return result
      },
    }
    const observed = new Proxy(target, proxyConf)
    return observed; // 返回代理对象
  }

  let data = {
    name: "wc",
    age: 18,
    info: {
      city: "bj",
      a: {
        b: {
          c: {
            d: 110
          }
        }
      }
    },
    score: [1, 2, 3]
  }

  const proxyData = reactive(data);
  // console.log(proxyData.name);
  // console.log(proxyData.info);
  // console.log(proxyData.info.city);
  // console.log(proxyData.info.a);
  // console.log(proxyData.info.a.b);

  // proxyData.name = "xq";  // 修改属性
  // proxyData.gender = "man"  // 新装属性

  proxyData.score.push(4)

</script>